#include "portii.h"
#include "common.h"

#include <math.h>

#define PI 3.1415926535

using namespace Common;

extern u8 portalgun_png[];
extern u8 portii_png[];

extern u8 center_png[];

Portii::Portii(b2World* world)
{
	Image* portiiImage;
	Image* portalgunImage;
	Image* centerImage;
	
	portiiImage    = new Image();
	portalgunImage = new Image();

	centerImage = new Image();

    if(portiiImage->LoadImage(portii_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
    if(portalgunImage->LoadImage(portalgun_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	if(centerImage->LoadImage(center_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	
	//TODO Load Image
	_playerSprite.SetImage(portiiImage);
	_gunSprite.SetImage(portalgunImage);
	_center.SetImage(centerImage);
	
	b2BodyDef bodyDef;
	bodyDef.position.Set(0 / PIXELS_PER_UNIT, 0 / PIXELS_PER_UNIT);
	_body = world->CreateBody(&bodyDef);
	b2CircleDef circledef;
	
	circledef.radius = (portiiImage->GetWidth()/2.0) / PIXELS_PER_UNIT;
	
	circledef.density = DEFAULT_DENSITY;
	circledef.friction = DEFAULT_FRICTION;
	circledef.restitution = DEFAULT_RESTITUTION;
	
	_body->CreateShape(&circledef);
	_body->SetMassFromShapes();
	
	_dx =  0;
	_aimAngle = 0;
	_aimX = 0;
	_aimY = 0;
	
	_sightColor = (GXColor){255, 0, 0, 70};
	
	_world = world;
	
	_designatorEnabled = false;
}

Portii::~Portii()
{
	if(_body != NULL)
	{
		_world->DestroyBody(_body);
		_body = NULL;
	}
}

void Portii::SetLocation(b2Vec2* l)
{
	SetLocation(l->x, l->y);
}

void Portii::SetLocation(float x, float y)
{
	b2Vec2 pos(x/ PIXELS_PER_UNIT, y/PIXELS_PER_UNIT);
	
	_body->SetXForm(pos, _body->GetAngle());
}

void Portii::Accel(float dx)
{
	_dx += dx;
	
	if(_dx > MAX_PORTII_SPEED)
		_dx = MAX_PORTII_SPEED;
		
	if(_dx < MIN_PORTII_SPEED)
		_dx = MIN_PORTII_SPEED;
}

void Portii::SlowToStop()
{
	if(_dx > 0)
		Accel(-.1);
		
	if(_dx < 0)
		Accel(.1);
}

void Portii::Update()
{
    _body->ApplyForce(b2Vec2(_dx, 0) ,_body->GetPosition());
}
	
void Portii::AimLocation(float x, float y)
{
	_aimX = x;
	_aimY = y;

	b2Vec2 pos = _body->GetPosition();
	
	_aimAngle = (atan2(GetWorldY() - _aimY, GetWorldX() - _aimX)) * 180 / PI;
	
}
		
void Portii::Jump()
{

}

void Portii::RenderSight(float sightX, float sightY, float dx, float dy)
{
	if(_designatorEnabled)
	{
		b2Vec2 pos = _body->GetPosition();
		
		float x1 = PIXELS_PER_UNIT*pos.x+_playerSprite.GetWidth()/2.0 + dx;
		float y1 = PIXELS_PER_UNIT*pos.y+_playerSprite.GetHeight()/2.0 + dy;
		
		Mtx model;
		guMtxIdentity(model);
		GX_LoadPosMtxImm(model, GX_PNMTX0);

		GX_SetLineWidth(10,GX_TO_ONE);
		
		// Turn off texturing
		GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
		GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);

		// Draw a Quad
		GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 2);
		
		GX_Position2f32(x1, y1);
		GX_Color4u8(_sightColor.r, _sightColor.g, _sightColor.b, _sightColor.a);
		GX_Position2f32(sightX, sightY);
		GX_Color4u8(_sightColor.r, _sightColor.g, _sightColor.b, _sightColor.a);
		GX_End();
			
		// Turn texturing back on
		GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
		GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
	}
}

float Portii::GetWorldX()
{
	b2Vec2 pos = _body->GetPosition();
	return PIXELS_PER_UNIT*pos.x;
}

float Portii::GetWorldY()
{
	b2Vec2 pos = _body->GetPosition();
	return PIXELS_PER_UNIT*pos.y;
}

void Portii::EnterPortal(Portal* p)
{

    if(p->IsWalled() == false)
	{
		SetLocation(p->GetLocation());
	}
	else
	{
		SetLocation(p->GetLocation());
		
		float rads = (p->GetAngle() * M_PI / 180);
		
		b2Vec2 new_v;
		
		new_v.x = sin(rads);
		new_v.y = cos(rads);
		
		b2Vec2 v = _body->GetLinearVelocity();
		
		float mag = sqrt(v.x*v.x + v.y*v.y);
		
		new_v *= mag;
		
		_body->SetLinearVelocity(new_v);
	}
}

void Portii::Reset()
{
	b2Vec2 new_v;
	
	new_v.x = 0;
	new_v.y = 0;
	_body->SetLinearVelocity(new_v);
	_body->SetAngularVelocity(0);
}

void Portii::Render(float dx, float dy)
{
	_playerSprite.SetRotation((float)_body->GetAngle() / M_PI * 180.0);
	
	b2Vec2 pos = _body->GetPosition();
	
	_playerSprite.SetPosition(PIXELS_PER_UNIT*pos.x, PIXELS_PER_UNIT*pos.y);
	
	_playerSprite.Draw(dx, dy);
	
	_center.SetPosition((float)(PIXELS_PER_UNIT*pos.x)+_playerSprite.GetWidth()/2.0 - 2.0, (float)(PIXELS_PER_UNIT*pos.y)+_playerSprite.GetHeight()/2.0 - 2.0);
	
	_gunSprite.SetPosition(PIXELS_PER_UNIT*pos.x, PIXELS_PER_UNIT*pos.y);
	_gunSprite.SetRotation((_aimAngle/2.0)+90.0);
	_gunSprite.Draw(dx, dy);
}
